package cc.rengu.igas.route.core.service.trans;

import cc.rengu.igas.route.common.constant.SmartRouteParamConstant;
import cc.rengu.igas.route.common.dao.NonFinanceTxnRouteCustomMapper;
import cc.rengu.igas.route.common.dao.impl.NonFinanceTxnRouteCustomMapperImpl;
import cc.rengu.igas.route.common.enums.RouteTxnNumEnum;
import cc.rengu.igas.route.common.enums.SmartRouteRspEnums;
import cc.rengu.igas.route.common.util.IPv4Util;
import cc.rengu.igas.route.core.realize.payment.DstChannelPaymentSignVerifyService;
import cc.rengu.igas.route.facade.bean.PayerInfo;
import cc.rengu.igas.route.facade.request.IntelligencePaymentSignVerifyRequest;
import cc.rengu.igas.route.facade.response.IntelligencePaymentSignVerifyResponse;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.entity.NonFinanceTxn;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.realize.RespCodeService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.RespCodeServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.DateUtil;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.base.StringUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 智能路由对外收款签约确认
 *
 * @author xionglz
 * @version 1.0
 * @date 2020-04-28
 */
public class IntelligencePaymentSignVerifyService extends RadpService {
    private RgLogger rgLog = RgLog.getLogger(this.getClass().getName());

    @Override
    protected int bizInit(String s) {
        return 0;
    }

    @Override
    protected int bizProcess(String s, int i) {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        try {
            IntelligencePaymentSignVerifyRequest signVerifyRequest = new IntelligencePaymentSignVerifyRequest();
            ConvertUtil.convertOutput(signVerifyRequest);
            if (cc.rengu.oltp.utility.util.StringUtil.isEmptyOrNull(signVerifyRequest.getFrontChannelId())) {
                rglog.error("必须上送前置渠道标志[frontChannelId]");
                throw new BizException(SmartRouteRspEnums.MSG_VALID_CHECK_ERROR.getRespCode(), SmartRouteRspEnums.MSG_VALID_CHECK_ERROR.getRespDesc());
            }

            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID, signVerifyRequest.getHeader().getSrcSysId());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM, signVerifyRequest.getHeader().getTraceNo());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRANS_TIME, signVerifyRequest.getHeader().getTransTime());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRANS_DATE, signVerifyRequest.getHeader().getTransDate());

            //查询非金融交易流水表获取签约时的通道
            NonFinanceTxnRouteCustomMapper nonFinanceTxnMapper = new NonFinanceTxnRouteCustomMapperImpl();
            List<NonFinanceTxn> nonFinanceTxns = nonFinanceTxnMapper.fetchTxnByFrontSeqNumWithNoDateTime(
                    signVerifyRequest.getHeader().getInstId(), signVerifyRequest.getOrigTxnDate(),
                    signVerifyRequest.getOrigOrder(), signVerifyRequest.getHeader().getSrcSysId(), signVerifyRequest.getHeader().getChanlId());
            if (nonFinanceTxns == null || nonFinanceTxns.size() != 1) {
                rgLog.error("根据原交易订单号：<origOrderId:{}>未查询到流水", signVerifyRequest.getOrigOrder());
                throw new BizException(SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespCode(), SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespDesc());
            }
            NonFinanceTxn nonFinanceTxn = nonFinanceTxns.get(0);
            if (StringUtil.isNullorEmpty(nonFinanceTxn.getDevInfo()) || StringUtil.isNullorEmpty(nonFinanceTxn.getRemark4())) {
                rgLog.error("根据原交易订单号：<origOrderId:{}>未查询原交易信息", signVerifyRequest.getOrigOrder());
                throw new BizException(SmartRouteRspEnums.TRANS_FAIL.getRespCode(), SmartRouteRspEnums.TRANS_FAIL.getRespDesc());
            }
            String dstChannelId = nonFinanceTxn.getDevBrand();
            if (StringUtil.isNullorEmpty(dstChannelId) || "".equals(dstChannelId.trim())) {
                rglog.error("未获取到原交易的支付通道");
                throw new BizException(SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespCode(), SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespDesc());
            }
            //处理原请求的付款方信息
            PayerInfo payerInfo = JSON.parseObject(new String(StringUtil.Base64ToBinary(nonFinanceTxn.getDevInfo()), StandardCharsets.UTF_8), PayerInfo.class);
            if (null == payerInfo) {
                rgLog.error("原付款方信息获取失败");
                throw new BizException(SmartRouteRspEnums.TRANS_FAIL.getRespCode(), SmartRouteRspEnums.TRANS_FAIL.getRespDesc());
            }
            //获取附加信息
            String addtionInfo = signVerifyRequest.getAdditionInfo();
            JSONObject jsonObject;
            if (!StringUtil.isNullorEmpty(addtionInfo)) {
                jsonObject = JSON.parseObject(addtionInfo);
            } else {
                jsonObject = new JSONObject();
            }
            //处理原交易请求的附加信息
            String addtionInfoOrig = nonFinanceTxn.getRemark4();
            if (!StringUtil.isNullorEmpty(addtionInfoOrig)) {
                JSONObject jsonObjectOrig = JSON.parseObject(addtionInfoOrig);
                if (null != jsonObjectOrig) {
                    jsonObjectOrig.forEach((key, value) -> {
                        if (!jsonObject.containsKey(key)) {
                            jsonObject.put(key, value);
                        } else {
                            jsonObject.put("orig" + key.substring(0, 1).toUpperCase() + key.substring(1), value);
                        }
                    });
                }
            }
            //处理原交易应答的附加信息
            String addtionInfoOrigRsp = nonFinanceTxn.getRemark5();
            if (!StringUtil.isNullorEmpty(addtionInfoOrigRsp)) {
                JSONObject jsonObjectOrigRsp = JSON.parseObject(addtionInfoOrigRsp);
                if (null != jsonObjectOrigRsp) {
                    jsonObjectOrigRsp.forEach((key, value) -> {
                        if (!jsonObject.containsKey(key)) {
                            jsonObject.put(key, value);
                        } else {
                            jsonObject.put("orig" + key.substring(0, 1).toUpperCase() + key.substring(1), value);
                        }
                    });
                }
            }
            signVerifyRequest.setAdditionInfo(jsonObject.toJSONString());
            jsonObject.forEach((key, value) -> {
                try {
                    xmlTreeUtil.setXmlTreeStringValue(key, (String) value);
                } catch (Exception e) {
                    rglog.error(e.getMessage());
                }
            });
            rglog.debug("附加信息:<{}>", signVerifyRequest.getAdditionInfo());
            //根据通道标识，通道交易码查询参数表
            SysParamService sysParamService = new SysParamServiceImpl();
            String paramType = SmartRouteParamConstant.PARAM_TYPE_PREFIX_CHANNEL_INSTANCE + dstChannelId;
            SysParam sysParam = sysParamService.getSysParamInfo(signVerifyRequest.getHeader().getInstId(), paramType, RouteTxnNumEnum.PAYMENT_SIGN_VERIFY.getTxnNum());
            if (sysParam == null || cc.rengu.oltp.utility.util.StringUtil.isEmptyOrNull(sysParam.getParamValue()) || !SmartRouteParamConstant.YES.equalsIgnoreCase(sysParam.getParamStatus())) {
                rglog.error("根据通道标识<channelId:{}>，通道交易码<channelTxnId:{}>未找到当前法人<{}>或公共实现类，使用通用实现类", paramType, RouteTxnNumEnum.PAYMENT_SIGN_VERIFY.getTxnNum(), signVerifyRequest.getHeader().getInstId());
                throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
            }

            //反射获取对应服务实例
            Class c = Class.forName(sysParam.getParamValue());
            DstChannelPaymentSignVerifyService signVerifyService = (DstChannelPaymentSignVerifyService) c.newInstance();

            //通道压力+1
            boolean isIncrSucc = true;
            String keyStress = SmartRouteParamConstant.ROUTE_DATA_ALL_STRESS + ":" + AppParamConstant.DEFAULT_INSTID + ":" + dstChannelId;
            try {
                RedisUtil.onceIncr(keyStress);
            } catch (Exception e) {
                rglog.warn(cc.rengu.utility.base.StringUtil.ExceptionToString(e));
                isIncrSucc = false;
            }
            IntelligencePaymentSignVerifyResponse signVerifyResponse = null;
            long channelStartTime = DateUtil.getCurrentTimeStamp();
            try {
                //调用通道签约确认
                signVerifyResponse = signVerifyService.paymentSignVerify(signVerifyRequest, payerInfo, nonFinanceTxn.getSysSeqNum());
            } finally {
                //调用通道的结束,设置通道耗时
                long channelEndTime = DateUtil.getCurrentTimeStamp();
                String timeCost = Long.valueOf(channelEndTime - channelStartTime).toString();
                String time13 = DateUtil.getCurrentDate() + DateUtil.getCurrentTime().substring(0, 5);
                String redisKey = AppParamConstant.DEFAULT_INSTID + ":" + dstChannelId;
                String nodeKey = redisKey + ":" + IPv4Util.ipv4Address;
                String transTimeKey = SmartRouteParamConstant.ROUTE_DATA_ALL_TIMECOST + ":" + redisKey + ":" + time13;
                String transTimeNodeKey = SmartRouteParamConstant.ROUTE_DATA_ALL_TIMECOST + ":" + nodeKey + ":" + time13;
                List<String> transTimeSplitList = RedisUtil.getListRange(transTimeKey, 0, 1);
                RedisUtil.onceRightPush(transTimeKey, timeCost);
                RedisUtil.onceRightPush(transTimeNodeKey, timeCost);
                if (null == transTimeSplitList || transTimeSplitList.isEmpty()) {
                    RedisUtil.onceExpire(transTimeKey, 300);
                    RedisUtil.onceExpire(transTimeNodeKey, 300);
                }
                //通道调用成功，redis计数器自减1(通道压力减少1)
                try {
                    if (isIncrSucc) {
                        RedisUtil.onceDecr(keyStress);
                    }
                } catch (Exception e) {
                    rglog.warn("通道<{}>压力统计redis计数器压力值-1异常{}", dstChannelId, cc.rengu.utility.base.StringUtil.ExceptionToString(e));
                }
            }

            //设置返回值
            signVerifyResponse.setDstChannelId(dstChannelId);

            //转换应答码状态
            RespCodeService respCodeService = new RespCodeServiceImpl();
            BizResponse<IntelligencePaymentSignVerifyResponse> response = new BizResponse<IntelligencePaymentSignVerifyResponse>();
            response.setResult(signVerifyResponse);
            response.setRespCode(signVerifyResponse.getRespCode());
            response.setRespDesc(signVerifyResponse.getRespDesc());
            response.setRspSysId(signVerifyResponse.getDstChannelId());
            //对于不能同步返回业务结果的通道，实现时一定要注意将受理成功的应答码对应的结果配置成处理中（即交易未知）
            TransStatusEnum transStatusEnum = respCodeService.transferRespCode(response.getRspSysId(), response.getRespCode(), response.getRespDesc());
            response.setTransStatus(transStatusEnum);
            xmlTreeUtil.deleteXmlTreeNode("status");
            if (TransStatusEnum.TRANS_SUCC.getStatus().equals(response.getTransStatus().getStatus())) {
                //成功
                signVerifyResponse.setStatus("0");
                rglog.info("交易成功");
            } else if (TransStatusEnum.TRANS_INIT.getStatus().equals(response.getTransStatus().getStatus()) ||
                    TransStatusEnum.TRANS_TIMEOUT.getStatus().equals(response.getTransStatus().getStatus())) {
                //未知
                signVerifyResponse.setStatus("2");
                rglog.info("交易未知");
            } else {
                //失败
                signVerifyResponse.setStatus("1");
                rglog.info("交易失败");
            }
            ConvertUtil.convertInput(signVerifyResponse);
            //明确成功计入成功
            if (TransStatusEnum.TRANS_SUCC.getStatus().equals(transStatusEnum.getStatus())) {
                String keySuccCount = SmartRouteParamConstant.ROUTE_DATA_ALL_SUCC_COUNT + ":" + AppParamConstant.DEFAULT_INSTID + ":" + dstChannelId;
                try {
                    RedisUtil.onceIncr(keySuccCount);
                } catch (Exception e) {
                    rglog.warn("通道<{}>成功交易总比数统计redis计数器+1异常{}", dstChannelId, cc.rengu.utility.base.StringUtil.ExceptionToString(e));
                }
            }
        } catch (BizException e) {
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, e.getCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, e.getMessage());
            } catch (Exception e1) {
                rglog.error(cc.rengu.utility.base.StringUtil.ExceptionToString(e1));
            }
        } catch (Exception e) {
            rglog.error(cc.rengu.utility.base.StringUtil.ExceptionToString(e));
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, SmartRouteRspEnums.TRANS_FAIL.getRespCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, SmartRouteRspEnums.TRANS_FAIL.getRespDesc());
            } catch (Exception e1) {
                rglog.error(cc.rengu.utility.base.StringUtil.ExceptionToString(e1));
            }
        }
        return 0;
    }

    @Override
    protected int bizTerminate(String s) {
        return 0;
    }
}
